package com.start.common.dataImport;

import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.ReflectUtil;
import cn.hutool.core.util.URLUtil;
import cn.hutool.poi.excel.ExcelReader;
import cn.hutool.poi.excel.ExcelUtil;
import cn.hutool.poi.excel.ExcelWriter;
import com.alibaba.fastjson2.JSONObject;
import com.start.common.configs.StartTokenConfig;
import com.start.common.dic.DictMapperParams;
import com.start.common.dic.DictMapperParamsUtils;
import com.start.common.dic.StartBaseDicMapperHandler;
import com.start.common.exceptions.StartBusException;
import com.start.common.tools.ClassTools;
import jakarta.servlet.http.HttpServletResponse;
import org.apache.commons.lang3.StringUtils;

import java.io.*;
import java.lang.reflect.Field;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 导入导出工具
 */
public class ImportExportUtils {

    public static <T> List<T> importExcelFile(Class<? extends T> clazz, String filePath) {
        if (StringUtils.isEmpty(filePath)) {
            throw new StartBusException("文件路径不能为空！");
        }
        File file = new File(filePath);
        return importExcelFile(clazz, file);
    }

    public static <T> List<T> importExcelFile(Class<? extends T> clazz, File file) {
        if (file == null) throw new StartBusException("文件不能为空");
        if (!file.exists()) {
            throw new StartBusException("文件不存在:" + file.getAbsolutePath());
        }
        if (!file.isFile()) {
            throw new StartBusException("该文件不是文件");
        }
        BufferedInputStream inputStream = FileUtil.getInputStream(file);
        return importExcelFile(clazz, inputStream);
    }

    /**
     * 导入文件
     *
     * @param clazz
     * @param inputStream
     * @param <T>
     * @return
     */
    public static <T> List<T> importExcelFile(Class<? extends T> clazz, InputStream inputStream) {
        DictMapperParams dictMapperParams = DictMapperParamsUtils.getExcelMapperParams(clazz, ExcelActionType.EXCEL_IMPORT);
        if (dictMapperParams == null) return null;
        ExcelReader excelReader = getExcelReader(inputStream);
        List<Map<String, Object>> readAll = importExcelFile(excelReader, dictMapperParams);
        return listMapToEntity(clazz, dictMapperParams, readAll);
    }

    /**
     * 导入文件
     *
     * @param clazz
     * @param dictMapperParams
     * @param mapList
     * @param <T>
     * @return
     */
    public static <T> List<T> listMapToEntity(Class<? extends T> clazz, DictMapperParams dictMapperParams, List<Map<String, Object>> mapList) {
        List<T> listData = new ArrayList<>();
        Set<String> handlerFieldNames = dictMapperParams.getHandlerFiled().keySet();
        for (Map<String, Object> entityMap : mapList) {
            T entity;
            try {
                entity = clazz.newInstance();
            } catch (InstantiationException | IllegalAccessException e) {
                e.printStackTrace();
                continue;
            }
            for (String fieldName : handlerFieldNames) {
                if (!entityMap.containsKey(fieldName)) continue;

                StartBaseDicMapperHandler excelMapperHandler = dictMapperParams.getHandlerFiled().get(fieldName);
                if (entityMap.get(fieldName) == null || entityMap.get(fieldName).toString().length() < 1) continue;
                Object fieldValue = excelMapperHandler.getImportValue(entityMap.get(fieldName).toString());
                if (fieldValue == null) continue;
                Field field = ReflectUtil.getField(clazz, fieldName);
                ReflectUtil.setFieldValue(entity, field, fieldValue);
            }
            listData.add(entity);
        }
        return listData;
    }

    public static ExcelReader getExcelReader(InputStream inputStream) {
        return ExcelUtil.getReader(inputStream);
    }

    public static List<Map<String, Object>> importExcelFile(ExcelReader excelReader, DictMapperParams dictMapperParams) {
        excelReader.setHeaderAlias(dictMapperParams.getHeaderAlias());
        return excelReader.readAll();
    }


    public static <T> void exportExcel(Class<? extends T> clazz, List<T> listData, HttpServletResponse response, String fileName) {
        exportExcel(clazz, listData, response, null, fileName);
    }

    public static <T> void exportExcel(Class<? extends T> clazz, List<T> listData, HttpServletResponse response, List<String> fields, String fileName) {
        setHttpServletResponseToFile(response, fileName);
        try {
            exportExcel(clazz, listData, fields, response.getOutputStream());
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static void setHttpServletResponseToFile(HttpServletResponse response, String fileName) {
        String codedFileName = new String(fileName.getBytes(StandardCharsets.UTF_8));
        codedFileName = URLUtil.encode(codedFileName);
        response.setHeader("Pragma", "no-cache");
        response.setHeader("Expires", "0");
        response.setHeader("Last-Modified", new Date().toString());
        response.setHeader("ETag", String.valueOf(System.currentTimeMillis()));
        response.setHeader("Cache-Control", "no-cache, no-store, must-revalidate");
        response.setContentType("application/octet-stream;charset=UTF-8");
        response.setHeader("content-disposition", "attachment;filename=" + codedFileName);
    }

    /**
     * 数据导出
     *
     * @param clazz
     * @param listData
     * @param outputStream
     * @param <T>
     */
    public static <T> void exportExcel(Class<? extends T> clazz, List<T> listData, List<String> fields, OutputStream outputStream) {
        List<Field> classFields = ClassTools.getEffectiveFields(clazz);
        if (fields == null || fields.isEmpty()) {
            DictMapperParams dictMapperParams = DictMapperParamsUtils.getExcelMapperParams(classFields, ExcelActionType.EXCEL_EXPORT, true);
            exportExcel(clazz, listData, dictMapperParams, outputStream);
            return;
        }

        Map<String, Field> fieldMap = classFields.stream().collect(Collectors.toMap(Field::getName, e -> e));
        List<Field> tempFields = new ArrayList<>();
        for (String fieldName : fields) {
            Field field = fieldMap.getOrDefault(fieldName, null);
            if (field == null) {
                throw new StartBusException("属性不存在：" + fieldName);
            }
            tempFields.add(field);
        }
        classFields = tempFields;
        DictMapperParams dictMapperParams = DictMapperParamsUtils.getExcelMapperParams(classFields, ExcelActionType.EXCEL_EXPORT, true);
        exportExcel(clazz, listData, dictMapperParams, outputStream);

    }

    public static <T> void exportExcel(Class<? extends T> clazz, List<T> listData, DictMapperParams dictMapperParams, OutputStream outputStream) {
        ExcelWriter writer = ExcelUtil.getWriter();
        writer.setHeaderAlias(dictMapperParams.getHeaderAlias());
        List<Map<String, Object>> list = listEntityDataTransform(listData, dictMapperParams);
        writer.write(list, true);
        writer.flush(outputStream);
    }

    public static <T> List<Map<String, Object>> listEntityDataTransform(List<T> listData, DictMapperParams dictMapperParams) {
        Map<String, StartBaseDicMapperHandler> handlerFiled = dictMapperParams.getHandlerFiled();
        Set<Map.Entry<String, StartBaseDicMapperHandler>> entries = handlerFiled.entrySet();
        List<Map<String, Object>> result = new ArrayList<>();
        for (T entity : listData) {
            Map<String, Object> map = new HashMap<>();
            for (Map.Entry<String, StartBaseDicMapperHandler> entry : entries) {
                Object value = entry.getValue().getExportValue(entity);
                map.put(entry.getValue().getFieldName(), value);
            }
            if (map.size() < 1) continue;
            result.add(map);
        }
        return result;
    }

    /**
     * 数据导出
     *
     * @param listData
     * @param dictMapperParams
     * @param outputStream
     */
    public static void exportExcel(List<Map<String, Object>> listData, DictMapperParams dictMapperParams, OutputStream outputStream) {
        ExcelWriter writer = ExcelUtil.getWriter();
        writer.setHeaderAlias(dictMapperParams.getHeaderAlias());
        writer.write(listData, true);
        writer.flush(outputStream);
    }

    public static <T> void createImportTemplate(Class<? extends T> clazz, HttpServletResponse response, String fileName) throws IOException {
        response.reset();
        setHttpServletResponseToFile(response, fileName);
        createImportTemplate(clazz, response.getOutputStream());
        response.flushBuffer();
    }

    public static <T> void createImportTemplate(Class<? extends T> clazz, OutputStream outputStream) {
        DictMapperParams dictMapperParams = DictMapperParamsUtils.getExcelMapperParams(clazz, ExcelActionType.EXCEL_EXPORT);
        createImportTemplate(dictMapperParams, outputStream);
    }

    /**
     * 创建导入模板
     *
     * @param dictMapperParams
     * @param response
     * @throws IOException
     */
    public static void createImportTemplate(DictMapperParams dictMapperParams, HttpServletResponse response) throws IOException {
        createImportTemplate(dictMapperParams, response.getOutputStream());
    }

    /**
     * 创建导入模板
     *
     * @param dictMapperParams
     * @param outputStream
     */
    public static void createImportTemplate(DictMapperParams dictMapperParams, OutputStream outputStream) {
        ExcelWriter writer = ExcelUtil.getWriter();
        Collection<String> values = dictMapperParams.getHeaderAlias().values();
        writer.writeRow(values, true);
        writer.flush(outputStream, true);
    }

    /**
     * 数据导出
     *
     * @param listData
     */
    public static void exportExcel(List<JSONObject> listData, JSONObject formOption, StartTokenConfig tokenConfig, String userToken, HttpServletResponse response, String fileName) throws IOException {
        setHttpServletResponseToFile(response, fileName);
        DictMapperParams excelMapperParams = DictMapperParamsUtils.getExcelMapperParams(formOption, ExcelActionType.EXCEL_EXPORT, tokenConfig, userToken);
        JONSExportExcel(listData, excelMapperParams, response.getOutputStream());

    }

    /**
     * 数据导出
     *
     * @param listData
     * @param dictMapperParams
     * @param outputStream
     */
    public static void JONSExportExcel(List<JSONObject> listData, DictMapperParams dictMapperParams, OutputStream outputStream) {
        ExcelWriter writer = ExcelUtil.getWriter();
        writer.setHeaderAlias(dictMapperParams.getHeaderAlias());
        writer.write(listData, true);
        writer.flush(outputStream);
    }

    public static List<JSONObject> importExcelFile(JSONObject tableOption, StartTokenConfig tokenConfig, String userToken, String filePath) {
        DictMapperParams excelMapperParams = DictMapperParamsUtils.getExcelMapperParams(tableOption, ExcelActionType.EXCEL_EXPORT, tokenConfig, userToken);
        if (excelMapperParams == null) return null;
        File file = new File(filePath);
        if (!file.exists()) {
            throw new StartBusException("文件不存在:" + file.getAbsolutePath());
        }
        if (!file.isFile()) {
            throw new StartBusException("该文件路径是一个目录");
        }
        BufferedInputStream inputStream = FileUtil.getInputStream(file);
        ExcelReader excelReader = getExcelReader(inputStream);
        List<Map<String, Object>> readAll = importExcelFile(excelReader, excelMapperParams);
        List<JSONObject> result = new ArrayList<>(readAll.size());
        for (int i = 0; i < readAll.size(); i++) {
            result.add(result.get(i));
        }
        return result;
    }
}
